home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-04 / gs24src.zip / BDFTOPS.PS < prev    next >
Text File  |  1992-02-01  |  24KB  |  765 lines

  1. %    Copyright (C) 1990, 1991 Aladdin Enterprises.  All rights reserved.
  2. %    Distributed by Free Software Foundation, Inc.
  3. %
  4. % This file is part of Ghostscript.
  5. %
  6. % Ghostscript is distributed in the hope that it will be useful, but
  7. % WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
  8. % to anyone for the consequences of using it or for whether it serves any
  9. % particular purpose or works at all, unless he says so in writing.  Refer
  10. % to the Ghostscript General Public License for full details.
  11. %
  12. % Everyone is granted permission to copy, modify and redistribute
  13. % Ghostscript, but only under the conditions described in the Ghostscript
  14. % General Public License.  A copy of this license is supposed to have been
  15. % given to you along with Ghostscript so you can know your rights and
  16. % responsibilities.  It should be in a file named COPYING.  Among other
  17. % things, the copyright notice and this notice must be preserved on all
  18. % copies.
  19.  
  20. % bdftops.ps
  21. % Convert a BDF file (possibly with (an) associated AFM file(s))
  22. % to a Ghostscript font.
  23.  
  24. % Ghostscript fonts are in the same format as Adobe Type 1 fonts,
  25. % except that they do not use eexec encryption.
  26. % See gs_fonts.ps for more information.
  27.  
  28. /envBDF 120 dict def
  29. envBDF begin
  30.  
  31. % "Import" the font-writing package.
  32.    (wrfont.ps) run
  33.  
  34. % Define lenIV (the number of initial random bytes in the encoded outlines).
  35. % This should be zero, but we set it to 4 for compatibility with PostScript.
  36.    /lenIV 4 def
  37.  
  38. % Invert the StandardEncoding vector.
  39.    256 dict dup begin
  40.    0 1 255 { dup StandardEncoding exch get exch def } for
  41.    end /decoding exch def
  42.  
  43. % Define the dictionary equivalent of ].
  44.    /dicttomark
  45.     { counttomark 2 idiv dup dict begin
  46.        { def } repeat
  47.       pop currentdict end 
  48.     } bind def
  49.  
  50. % Define the properties copied to FontInfo.
  51.    mark
  52.      (COPYRIGHT) /Notice
  53.      (FAMILY_NAME) /FamilyName
  54.      (FULL_NAME) /FullName
  55.      (WEIGHT_NAME) /Weight
  56.    dicttomark /properties exch def
  57.  
  58. % Define the character sequences used to fill in some undefined entries
  59. % in the standard encoding.
  60.    mark
  61.      (exclamdown) [/exclam]
  62.      (fraction) [/slash]
  63.      (florin) [/f]
  64.      (quotesingle) [/quoteright]
  65.      (quotedblleft) [/quotedbl]
  66.      (guillemotleft) [/less /less]
  67.      (guilsinglleft) [/less]
  68.      (guilsinglright) [/greater]
  69.      (fi) [/f /i]
  70.      (fl) [/f /l]
  71.      (endash) [/hyphen /hyphen]
  72.      (periodcentered) [/asterisk]
  73.      (bullet) [/asterisk]
  74.      (quotesinglbase) [/quotesingle]
  75.      (quotedblbase) [/quotedbl]
  76.      (quotedblright) [/quotedbl]
  77.      (guillemotright) [/greater /greater]
  78.      (ellipsis) [/period /period /period]
  79.      (questiondown) [/question]
  80.      (grave) [/quoteleft]
  81.      (acute) [/quoteright]
  82.      (circumflex) [/asciicircum]
  83.      (tilde) [/asciitilde]
  84.      (dieresis) [/quotedbl]
  85.      (cedilla) [/comma]
  86.      (hungarumlaut) [/quotedbl]
  87.      (emdash) [/hyphen /hyphen /hyphen]
  88.      (AE) [/A /E]
  89.      (OE) [/O /E]
  90.      (ae) [/a /e]
  91.      (dotlessi) [/i]
  92.      (oe) [/o /e]
  93.      (germandbls) [/s /s]
  94.    dicttomark /composites exch def
  95.  
  96. % Note the characters that must be defined as subroutines.
  97.    96 dict begin
  98.      0 composites
  99.       { exch pop
  100.          { dup currentdict exch known
  101.         { pop }
  102.         { 1 index def 1 add }
  103.        ifelse
  104.      }
  105.     forall
  106.       }
  107.      forall pop
  108.      currentdict
  109.    end /subrchars exch def
  110.  
  111. % Define the overstruck characters that can be synthesized with seac.
  112.    mark
  113.     [ /Aacute /Acircumflex /Adieresis /Agrave /Aring /Atilde
  114.       /Ccedilla
  115.       /Eacute /Ecircumflex /Edieresis /Egrave
  116.       /Iacute /Icircumflex /Idieresis /Igrave
  117.       /Ntilde
  118.       /Oacute /Ocircumflex /Odieresis /Ograve /Otilde
  119.       /Scaron
  120.       /Uacute /Ucircumflex /Udieresis /Ugrave
  121.       /Yacute /Ydieresis
  122.       /Zcaron
  123.       /aacute /acircumflex /adieresis /agrave /aring /atilde
  124.       /ccedilla
  125.       /eacute /ecircumflex /edieresis /egrave
  126.       /iacute /icircumflex /idieresis /igrave
  127.       /ntilde
  128.       /oacute /ocircumflex /odieresis /ograve /otilde
  129.       /scaron
  130.       /uacute /ucircumflex /udieresis /ugrave
  131.       /yacute /ydieresis
  132.       /zcaron
  133.     ]
  134.     { dup dup length string cvs
  135.       [ exch dup 0 1 getinterval
  136.         exch dup length 1 sub 1 exch getinterval
  137.       ]
  138.     } forall
  139.      /cent [/c /slash]
  140.      /sterling [/L /hyphen]
  141.      /yen [/Y /equal]
  142.      /daggerdbl [/bar /equal]
  143.    dicttomark /accentedchars exch def
  144.  
  145. % Define the Type 1 opcodes we care about.
  146.    /c_callsubr 10 def   /s_callsubr <0a> def
  147.    /c_return 11 def
  148.    /c_escape 12 def
  149.      /ce_seac 6 def   /s_seac <0c06> def
  150.      /ce_sbw 7 def   /s_sbw <0c07> def
  151.      /ce_setcurrentpoint 33 def   /s_setcurrentpoint <0c21> def
  152.    /c_hsbw 13 def   /s_hsbw <0d> def
  153.    /c_endchar 14 def   /s_endchar <0e> def
  154.    /c_hmoveto 22 def
  155.      /s_setcurrentpoint_hmoveto s_setcurrentpoint <8b16> concatstrings def
  156.  
  157. % ------ BDF file parsing utilities ------ %
  158.  
  159. % Define a buffer for reading the BDF file.
  160.    /buffer 400 string def
  161.  
  162. % Read a line from the BDF file into the buffer.
  163. % Define /keyword as the first word on the line.
  164. % Define /args as the remainder of the line.
  165. % If the keyword is equal to commentword, skip the line.
  166. % (If commentword is equal to a space, never skip.)
  167.    /nextline
  168.     { bdfile buffer readline not
  169.        { (Premature EOF\n) print stop } if
  170.       ( ) search
  171.        { /keyword exch def pop }
  172.        { /keyword exch def () }
  173.       ifelse
  174.       /args exch def
  175.       keyword commentword eq { nextline } if
  176.     } bind def
  177.  
  178. % Get a word argument from args.  We do *not* copy the string.
  179.    /warg        % warg -> string
  180.     { args ( ) search
  181.        { exch pop exch }
  182.        { () }
  183.       ifelse  /args exch def
  184.     } bind def
  185.  
  186. % Get an integer argument from args.
  187.    /iarg        % iarg -> int
  188.     { warg cvi
  189.     } bind def
  190.  
  191. % Get a numeric argument from args.
  192.    /narg        % narg -> int|real
  193.     { warg cvr
  194.       dup dup cvi eq { cvi } if
  195.     } bind def
  196.  
  197. % Convert the remainder of args into a string.
  198.    /remarg        % remarg -> string
  199.     { args copystring
  200.     } bind def
  201.  
  202. % Get a string argument that occupies the remainder of args.
  203.    /sarg        % sarg -> string
  204.     { args (") anchorsearch
  205.        { pop /args exch def } { pop } ifelse
  206.       args args length 1 sub get (") 0 get eq
  207.        { args 0 args length 1 sub getinterval /args exch def } if
  208.       args copystring
  209.     } bind def
  210.  
  211. % Check that the keyword is the expected one.
  212.    /checkline        % (EXPECTED-KEYWORD) checkline ->
  213.     { dup keyword ne
  214.        { (Expected ) print =
  215.          (Line=) print keyword print ( ) print args print (\n) print stop
  216.        } if
  217.       pop
  218.     } bind def
  219.  
  220. % Read a line and check its keyword.
  221.    /getline        % (EXPECTED-KEYWORD) getline ->
  222.     { nextline checkline
  223.     } bind def
  224.  
  225. % Find the first/last non-zero bit of a non-zero byte.
  226.    /fnzb
  227.     { 0 { exch dup 128 ge { pop exit } { dup add exch 1 add } ifelse }
  228.       loop
  229.     } bind def
  230.    /lnzb
  231.     { 7 { exch dup 1 and 0 ne { pop exit } { -1 bitshift exch 1 sub } ifelse }
  232.       loop
  233.     } bind def
  234.  
  235. % ------ Type 1 encoding utilities ------ %
  236.  
  237. % Parse the side bearing and width information that begins a CharString.
  238. % Arguments: charstring.  Result: mark sbx wx substring *or*
  239. % mark sbx sby wx wy substring.
  240.    /parsesbw
  241.     { mark exch lenIV
  242.        {        % stack: mark ... string dropcount
  243.          dup 2 index length exch sub getinterval
  244.      dup 0 get dup 32 lt { pop exit } if
  245.      dup 246 le
  246.       { 139 sub exch 1 }
  247.       { dup 250 le
  248.          { 247 sub 8 bitshift 108 add 1 index 1 get add exch 2 }
  249.          { dup 254 le
  250.             { 251 sub 8 bitshift 108 add 1 index 1 get add neg exch 2 }
  251.         { pop dup 1 get 128 xor 128 sub
  252.           8 bitshift 1 index 2 get add
  253.           8 bitshift 1 index 3 get add
  254.           8 bitshift 1 index 4 get add exch 5
  255.         } ifelse
  256.          } ifelse
  257.       } ifelse
  258.        } loop
  259.     } bind def 
  260.  
  261. % Find the side bearing and width information that begins a CharString.
  262. % Arguments: charstring.  Result: charstring sizethroughsbw.
  263.    /findsbw
  264.     { dup parsesbw counttomark 1 add 1 roll cleartomark skipsbw
  265.     } bind def
  266.    /skipsbw        % charstring sbwprefix -> sizethroughsbw
  267.     { length 1 index length exch sub
  268.       2 copy get 12 eq { 2 } { 1 } ifelse add
  269.     } bind def
  270.  
  271. % Encode a number, and append it to a string.
  272. % Arguments: str num.  Result: newstr.
  273.    /concatnum
  274.     { dup dup -107 ge exch 107 le and
  275.        { 139 add 1 string dup 0 3 index put }
  276.        { dup dup -1131 ge exch 1131 le and
  277.           { dup 0 ge { 16#f694 } { neg 16#fa94 } ifelse add
  278.         2 string dup 0 3 index -8 bitshift put
  279.         dup 1 3 index 255 and put
  280.       }
  281.       { 5 string dup 0 255 put exch
  282.         2 copy 1 exch -24 bitshift 255 and put
  283.         2 copy 2 exch -16 bitshift 255 and put
  284.         2 copy 3 exch -8 bitshift 255 and put
  285.         2 copy 4 exch 255 and put
  286.         exch
  287.       }
  288.      ifelse
  289.        }
  290.       ifelse exch pop concatstrings
  291.     } bind def
  292.  
  293. % Encode a subroutine call for a given character, appending it to a string.
  294. % Arguments: str subrindex.  Result: newstr.
  295.    /concatcall
  296.     { () exch concatnum
  297.       s_callsubr concatstrings concatstrings
  298.     } bind def
  299.  
  300. % ------ Point arithmetic utilities ------ %
  301.  
  302.    /ptadd { exch 4 -1 roll add 3 1 roll add } bind def
  303.  
  304.    /ptexch { 4 2 roll } bind def
  305.  
  306.    /ptneg { neg exch neg exch } bind def
  307.  
  308.    /ptsub { ptneg ptadd } bind def
  309.  
  310. % ------ The main program ------ %
  311.  
  312.    /readBDF        % infilename outfilename fontname encodingname
  313.             %   uniqueID readBDF -> font
  314.     { /uniqueID exch def
  315.       /encoding exch def
  316.       /fontname exch def
  317.       /psname exch def
  318.       /bdfname exch def
  319.       gsave        % so we can set the CTM to the font matrix
  320.  
  321. %  Open the input files.  We don't open the output file until
  322. %  we've done a minimal validity check on the input.
  323.       bdfname (r) file /bdfile exch def
  324.       /commentword ( ) def
  325.  
  326. %  Check for the STARTFONT.
  327.       (STARTFONT) getline
  328.       args (2.1) ne { (Not version 2.1\n) print stop } if
  329.  
  330. %  Initialize the font.
  331.       /Font 20 dict def
  332.       Font begin
  333.       /FontName fontname def
  334.       /PaintType 0 def
  335.       /FontType 1 def
  336.       /UniqueID uniqueID def
  337.       /Encoding encoding cvx exec def
  338.       /FontInfo 20 dict def
  339.       /Private 20 dict def
  340.       currentdict end currentdict end
  341.       exch begin begin        % insert font above environment
  342.  
  343. %  Initialize the Private dictionary in the font.
  344.       Private begin
  345.       /-! {string currentfile exch readhexstring pop} readonly def
  346.       /-| {string currentfile exch readstring pop} readonly def
  347.       /|- {readonly def} readonly def
  348.       /| {readonly put} readonly def
  349.       /BlueValues [] def
  350.       /lenIV lenIV def
  351.       /MinFeature {16 16} def
  352.       /password 5839 def
  353.       /UniqueID uniqueID def
  354.       end        % Private
  355.  
  356. %  Now open the output file.
  357.       psname (w) file /psfile exch def
  358.  
  359. %  Put out a header compatible with the Adobe "standard".
  360.       (%!FontType1-1.0: ) ws fontname wt (000.000) wl
  361.       (% This is a font description converted from ) ws
  362.         bdfname wl
  363.       (%   by bdftops running on revision ) ws
  364.       revision wt (of (a) ) ws
  365.       statusdict /product get ws (.) wl
  366.  
  367. %  Copy the initial comments, up to FONT.
  368.       true
  369.       { nextline
  370.         keyword (COMMENT) ne {exit} if
  371.     { (% Here are the initial comments from the BDF file:\n%) wl
  372.     } if false
  373.     (%) ws remarg wl
  374.       } loop pop
  375.       /commentword (COMMENT) def    % do skip comments from now on
  376.  
  377. %  Read and process the FONT, SIZE, and FONTBOUNDINGBOX.
  378.       % If we cared about FONT, we'd use it here.  If the BDF files
  379.       % from MIT had PostScript names rather than X names, we would
  380.       % care; but what's there is unusable, so we discard FONT.
  381.       (FONT) checkline
  382.       (SIZE) getline
  383.         /pointsize iarg def   /xres iarg def   /yres iarg def
  384.       (FONTBOUNDINGBOX) getline
  385.         /fbbw iarg def   /fbbh iarg def   /fbbxo iarg def   /fbbyo iarg def
  386.     /fraster fbbw 7 add 8 idiv def
  387.       nextline
  388.  
  389. % Allocate the buffers for the bitmap and the outline,
  390. % according to the font bounding box.
  391.       /bits fraster fbbh mul 200 max 65535 min string def
  392.       /outline bits length 6 mul 65535 min string def
  393.  
  394. %  The Type 1 font machinery really only works with a 1000 unit
  395. %  character coordinate system.  Set this up here.
  396.  
  397. % Compute the factor to make the X entry in the FontMatrix
  398. % come out at exactly 0.001.
  399.       /fontscale   72 pointsize div xres div 1000 mul   def
  400.       Font /FontBBox
  401.        [ fbbxo fontscale mul
  402.      fbbyo fontscale mul
  403.      fbbxo fbbw add fontscale mul
  404.      fbbyo fbbh add fontscale mul
  405.        ] cvx readonly
  406.       put
  407.  
  408. %  Read and process the properties.  We only care about a few of them.
  409.       keyword (STARTPROPERTIES) eq
  410.        { iarg
  411.           { nextline
  412.         properties keyword known
  413.          { FontInfo properties keyword get sarg readonly put
  414.          } if
  415.       } repeat
  416.          (ENDPROPERTIES) getline
  417.      nextline
  418.        } if
  419.  
  420. %  Compute and set the FontMatrix.
  421.       Font /FontMatrix
  422.        [ 0.001 0 0 0.001 xres mul yres div 0 0 ] readonly
  423.       dup setmatrix put
  424.  
  425. %  Read and process the header for the bitmaps.
  426.       (CHARS) checkline
  427.         /ccount iarg def
  428.  
  429. %  Initialize the character subroutine table and the CharStrings dictionary.
  430.       /subrs subrchars length array def
  431.       /subrsbw subrchars length array def
  432.       /subrcount 0 def
  433.       /charstrings ccount composites length add
  434.         accentedchars length add 1 add dict def        % 1 add for .notdef
  435.       /isfixedwidth true def
  436.       /fixedwidth null def
  437.  
  438. %  Read and process the bitmap data.  This reads the remainder of the file.
  439.       ccount -1 1
  440.        { (STARTCHAR) getline
  441.            /charname remarg def
  442.      (/) print charname print
  443.        10 mod 1 eq { (\n) print flush } if
  444.      (ENCODING) getline        % Ignore, assume StandardEncoding
  445.      (SWIDTH) getline
  446.        /swx iarg pointsize mul 1000 div xres mul 72 div def
  447.        /swy iarg pointsize mul 1000 div xres mul 72 div def
  448.      (DWIDTH) getline        % Ignore, use SWIDTH instead
  449.      (BBX) getline
  450.        /bbw iarg def  /bbh iarg def  /bbox iarg def  /bboy iarg def
  451.      nextline
  452.      keyword (ATTRIBUTES) eq
  453.       { nextline
  454.       } if
  455.      (BITMAP) checkline
  456.  
  457. %  Read the bits for this character.
  458.      bbw 7 add 8 idiv /raster exch def
  459. % The bitmap handed to type1imagepath must have the correct height,
  460. % because type1imagepath uses this to compute the scale factor,
  461. % so we have to clear the unused parts of it.
  462.      bits dup 0 1 raster fbbh mul 1 sub
  463.       { 0 put dup } for
  464.      pop pop
  465.      raster fbbh bbh sub mul   raster   raster fbbh 1 sub mul
  466.       { bits exch raster getinterval
  467.         bdfile buffer readline not
  468.          { (EOF in bitmap\n) print stop } if
  469.         % stack has <bits.interval> <buffer.interval>
  470.         0 () /SubFileDecode filter
  471.         exch 2 copy readhexstring pop pop pop closefile
  472.       } for
  473.      (ENDCHAR) getline
  474.  
  475. %  Compute the font entry, converting the bitmap to an outline.
  476.      bits 0 raster fbbh mul getinterval    % the bitmap image
  477.      bbw   fbbh                % bitmap width & height
  478.      swx   swy                % width x & y
  479.      bbox neg   bboy neg            % origin x & y
  480.          % Account for lenIV when converting the outline.
  481.      outline  lenIV  outline length lenIV sub  getinterval
  482.      type1imagepath
  483.      length lenIV add
  484.      outline exch 0 exch getinterval
  485.  
  486. % Check for a fixed width font.
  487.      isfixedwidth
  488.       { fixedwidth null eq
  489.          { /fixedwidth swx def }
  490.          { fixedwidth swx ne { /isfixedwidth false def } if }
  491.         ifelse
  492.       } if
  493.  
  494. % Check whether this character must be a subroutine.
  495. % If so, strip off the initial [h]sbw, replace the endchar by a return,
  496. % and put the charstring in the Subrs array.
  497.      subrchars charname known
  498.       { /charstr exch def
  499.         /csindex subrchars charname get def
  500.         charstr parsesbw counttomark 1 add 1 roll
  501.           counttomark 2 eq { 0 exch 0 } if ]
  502.           subrsbw exch csindex exch put
  503.           charstr exch skipsbw /charend exch def pop
  504.         charstr charstr length 1 sub c_return put
  505.         subrs   csindex
  506.           charstr   charend lenIV sub   dup charstr length exch sub
  507.             getinterval copystring
  508.         put
  509.         charstr 0 charend getinterval
  510.           () subrchars charname get concatcall s_endchar concatstrings
  511.           concatstrings
  512.         /subrcount subrcount 1 add def
  513.       }
  514.       { copystring }
  515.      ifelse
  516.      charname exch charstrings 3 1 roll put
  517.        } for
  518.       (ENDFONT) getline
  519.  
  520. %  Synthesize missing characters out of available ones.
  521. %  For fixed-width fonts, only do this in the 1-for-1 case.
  522.       composites
  523.        { 1 index charstrings exch known
  524.           { pop pop }
  525.       { dup isfixedwidth
  526.          { dup length 1 eq }
  527.          { true }
  528.         ifelse
  529.         exch { charstrings exch known and } forall
  530.          { ( /) print 1 index bits cvs print
  531.            dup length 1 eq
  532.             { 0 get charstrings exch get copystring }
  533.         { % Top of stack is array of characters to combine.
  534.           % Convert to an array of subr indices.
  535.           [ exch { subrchars exch get } forall ]
  536.           % The final width is the sum of the widths of all
  537.           % the characters, minus the side bearings of all the
  538.           % characters except the first.  After each character
  539.           % except the last, do a setcurrentpoint of its width
  540.           % minus its side bearing (except for the first character);
  541.           % before each character except the first, do a 0 hmoveto.
  542.           % Fortunately, all this information is available in subrsbw.
  543.           /combine exch def
  544.           lenIV string
  545.           % Compute the total width.
  546.           subrsbw combine 0 get get aload pop pop pop 2 copy
  547.           combine
  548.            { subrsbw exch get
  549.              aload pop ptexch ptsub ptadd
  550.            } forall
  551.           % Encode the combined side bearing and width.
  552.           dup 3 index or 0 eq
  553.            { pop exch pop 2 array astore s_hsbw }
  554.            { 4 array astore s_sbw }
  555.           ifelse
  556.           3 1 roll { concatnum } forall exch concatstrings
  557.           % Encode the subroutine calls, except the last.
  558.           subrsbw combine 0 get get aload pop ptexch pop pop
  559.           0 1 combine length 2 sub
  560.            { combine exch get /ccsi exch def
  561.              2 copy 5 -1 roll ccsi concatcall
  562.              3 -1 roll concatnum exch concatnum
  563.              s_setcurrentpoint_hmoveto concatstrings
  564.              subrsbw ccsi get aload pop ptexch ptsub
  565.              5 -2 roll ptadd
  566.            } for
  567.           % Encode the last call.
  568.           pop pop
  569.           combine dup length 1 sub get concatcall
  570.           s_endchar concatstrings
  571.         } ifelse
  572.            charstrings 3 1 roll put
  573.          }
  574.          { pop pop }
  575.         ifelse
  576.       }
  577.      ifelse
  578.        }
  579.       forall flush
  580.  
  581. %  Synthesize accented characters with seac if needed and possible.
  582.       accentedchars
  583.        { aload pop /accent exch def /base exch def
  584.          buffer cvs /accented exch def
  585.      charstrings accented known not
  586.      charstrings base known and
  587.      charstrings accent known and
  588.       { ( /) print accented print
  589.         charstrings base get findsbw 0 exch getinterval
  590.         /acstring exch def        % start with sbw of base
  591.         charstrings accent get parsesbw
  592.         counttomark 1 sub { pop } repeat    % just leave mark & sbx
  593.         acstring exch concatnum exch pop    % pop the mark
  594.         0 concatnum 0 concatnum        % adx ady
  595.         decoding base get concatnum        % bchar
  596.         decoding accent get concatnum    % achar
  597.         s_seac concatstrings
  598.         charstrings exch accented copystring exch put
  599.       } if
  600.        } forall
  601.  
  602. %  Make a CharStrings entry for .notdef.
  603.       outline lenIV <8b8b0d0e> putinterval    % 0 0 hsbw endchar
  604.       charstrings /.notdef outline 0 lenIV 4 add getinterval copystring put
  605.  
  606. %  Encrypt the CharStrings and Subrs (in place).
  607.       charstrings dup begin
  608.        { 4330 exch dup type1encrypt exch pop
  609.          readonly def
  610.        }
  611.       forall end
  612.       0 1 subrs length 1 sub
  613.        { dup subrs exch get dup null ne
  614.       { 4330 exch dup type1encrypt exch pop
  615.         subrs 3 1 roll put
  616.       }
  617.       { pop pop }
  618.      ifelse
  619.        }
  620.       for
  621.  
  622. %  Make most of the remaining entries in the font dictionaries.
  623.       Font /CharStrings charstrings readonly put
  624.       FontInfo /FullName known not
  625.        { % Some programs insist on FullName being present.
  626.          FontInfo /FullName FontName dup length string cvs put
  627.        }
  628.       if
  629.       FontInfo /isFixedPitch isfixedwidth put
  630.       subrcount 0 gt
  631.        { Private /Subrs subrs readonly put
  632.        } if
  633.  
  634. %  Determine the italic angle and underline position
  635. %  by actually installing the font.
  636.       save
  637.       /_temp_ Font definefont setfont
  638.       [1000 0 0 1000 0 0] setmatrix        % mitigate rounding problems
  639. % The italic angle is the multiple of -5 degrees
  640. % that minimizes the width of the 'I'.
  641.       0 9999 0 5 85
  642.        { dup rotate
  643.          newpath 0 0 moveto (I) false charpath
  644.      dup neg rotate
  645.          pathbbox pop exch pop exch sub
  646.      dup 3 index lt { 4 -2 roll } if
  647.      pop pop
  648.        }
  649.       for pop
  650. % The underline position is halfway between the bottom of the 'A'
  651. % and the bottom of the FontBBox.
  652.       newpath 0 0 moveto (A) false charpath
  653.       FontMatrix concat
  654.       pathbbox pop pop exch pop
  655. %  Put the values in FontInfo.
  656.       3 -1 roll restore
  657.       Font /FontBBox get 1 get add 2 div cvi
  658.       dup FontInfo /UnderlinePosition 3 -1 roll put
  659.       2 div abs FontInfo /UnderlineThickness 3 -1 roll put
  660.       FontInfo /ItalicAngle 3 -1 roll put
  661.  
  662. %  Clean up and finish.
  663.       grestore
  664.       bdfile closefile
  665.       Font currentdict end end begin        % remove font from dict stack
  666.       (\n) print flush
  667.  
  668.     } bind def
  669.  
  670. % ------ Reader for AFM files ------ %
  671.  
  672. % Dictionary for looking up character keywords
  673.    /cmdict 6 dict dup begin
  674.       /C { /c iarg def } def
  675.       /N { /n warg copystring def } def
  676.       /WX { /w narg def } def
  677.       /W0X /WX load def
  678.       /W /WX load def
  679.       /W0 /WX load def
  680.    end def
  681.  
  682.    /readAFM        % fontdict afmfilename readAFM -> fontdict
  683.     { (r) file /bdfile exch def
  684.       /Font exch def
  685.       /commentword (Comment) def
  686.  
  687. %  Check for the StartFontMetrics.
  688.       (StartFontMetrics) getline
  689.       args cvr 2.0 lt { (Not version 2.0 or greater\n) print stop } if
  690.  
  691. %  Look for StartCharMetrics, then parse the character metrics.
  692. %  The only information we care about is the X width.
  693.       /metrics 0 dict def
  694.        { nextline
  695.          keyword (EndFontMetrics) eq { exit } if
  696.      keyword (StartCharMetrics) eq
  697.       { iarg dup dict /metrics exch def
  698.          { /c -1 def /n null def /w null def
  699.            nextline buffer
  700.             { token not { exit } if
  701.           dup cmdict exch known
  702.            { exch /args exch def   cmdict exch get exec   args }
  703.            { pop }
  704.           ifelse
  705.         } loop
  706.            c 0 ge n null ne or w null ne and
  707.             { n null eq { /n Font /Encoding get c get def } if
  708.           metrics n w put
  709.         }
  710.            if
  711.          }
  712.         repeat
  713.         (EndCharMetrics) getline
  714.       } if
  715.        } loop
  716.  
  717. %  Insert the metrics in the font.
  718.        metrics length 0 ne
  719.         { Font /Metrics metrics readonly put
  720.     } if
  721.       Font
  722.     } bind def
  723.  
  724. end        % envBDF
  725.  
  726. % Enter the main program in the current dictionary.
  727. /bdftops
  728.  { [] exch bdfafmtops
  729.  } bind def
  730. /bdfafmtops        % infilename afmfilename* outfilename fontname
  731.             %   encoding uniqueID
  732.  { envBDF begin
  733.      6 -2 roll exch 6 2 roll    % afm* in out fontname encoding uniqueID
  734.      readBDF        % afm* font
  735.      exch { readAFM } forall
  736.      save exch
  737.      dup /FontName get exch definefont
  738.      setfont
  739.      psfile writefont
  740.      restore
  741.      psfile closefile
  742.    end
  743.  } bind def
  744.  
  745. % If the program was invoked from the command line, run it now.
  746. [ shellarguments
  747.  { counttomark 4 ge
  748.     { dup 0 get
  749.       dup 48 ge exch 57 le and        % last arg starts with a digit?
  750.        { cvi /StandardEncoding }        % no encodingname
  751.        { cvn exch cvi exch }            % have encodingname
  752.       ifelse
  753.       counttomark 4 roll
  754.       counttomark 5 sub array astore
  755.       6 -4 roll exch
  756.       bdfafmtops
  757.     }
  758.     { cleartomark
  759.       (Usage: bdftops xx.bdf [yy1.afm ...] zz.gsf fontname uniqueID [encodingname]\n) print flush
  760.       mark
  761.     }
  762.    ifelse
  763.  }
  764. if pop
  765.